在上一篇中我們介紹了 Tensorflow 在建置靜態計算圖的兩個主要類別:tf.Variable
和 tf.Graph
。今天我們會先花一點時間來舉說 tf.Session
物件。這個 tf.Session
可以看作是靜態計算圖和 runtime 之間的媒介。靜態計算圖在建置的過程中,特別為資料預留了型態和空間,再藉著 tf.Session
的 run
的方法將資料餵入,並取回計算結果。
tf.Session
A tf.Sessions
會使用 Tensorflow C++ backend 評估計算圖的計算結果。
使用實例方法 tf.Session().run()
來提供數據,然後獲取計算結果。有以下四種 scenarios 啟動 tf.Session()
tf.InteractiveSession()
並將操作置於 default 設備(應為 CPU)tf.Session()
該 tf.Session()
早將操作置於 default 設備(應為 CPU)tf.Session()
並將某些操作置於特定設備,如 GPU(需要關於 GPU 的配置知識)tf.train.ClusterSpec
到類別 factory 方法的 cluster_def
參數,啟動分散式叢集 Session。現就單線程(single thread),CPU 的方式來 demosrate 如何使用 tf.Session
作資料的餵入和擷取(Feed and fetch)。例子由 tensorflow 官方網站提供
import tensorflow as tf
import numpy as np
x = tf.placeholder(tf.float32, shape=(1024, 1024)) # use symbolic placeholder for data
y = tf.matmul(x, x)
with tf.Session() as sess: # using tf.Session within its active context
# print(sess.run(y)) # ERROR: will fail because x was not fed.
rand_array = np.random.rand(1024, 1024)
print(sess.run(y, feed_dict={x: rand_array})) # Will succeed.
然而,由於使用 Python 的使用者相當廣泛,雖然靜態計算圖有許多優點,但就是不包括 Python 使用者最希望擁有的優點,那就是可以使用 Python 圈子裡常被使用的函式庫,包括了 numpy 和 pandas 等等。同時,靜態計算圖也無法再建置時除錯,這對研究者經常要建置許多不同的網路架構,甚至得實驗不同網路架構間的特性,就顯得非常重要。PyTorch 的這項優點,恰巧搓中了 Tensorflow 的痛處,也讓 Tensorflow 引入了:
Eager execution 又被稱為 Eager mode:可以使用者在建置模型時,就評估每個操作。而根據官方文件,Eager execution 有下列設計目標:
tf.keras.layers
皆可以在 Eager mode 中使用tf.GradientTape()
context 來記錄正向的運算過程,並記錄到一個 "tape" 物件上。待該物件呼叫自身的 gradient
即可反向計算下面是一個官方提供使用的tf.GradientTape()
例子。這是和 PyTroch 很相近的設計,除了在 Eager mode 是用 with tf.GradientTape()
來納入正向傳播的運算,而 PyTroch 則是 with torch.no_grad()
的方法 exclude 正向傳播的運算。
import tensorflow as tf
tf.enable_eager_execution() # must enable eager mode immedately after importing
w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
loss = w * w
grad = tape.gradient(loss, w)
print(grad) # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)
在 Eager mode 可執行有狀態(如任何運行在 tf.Variable
的運算)和非有狀態操作。若在 Graph mode 則需要 tf.Session()
來提供資料計算。
Eager mode:
numpy.ndarray
或 tf.data API
(如:tf.data.Dataset.from_tensor_slices
)tf.device('/ gpu:0'
)numpy.ndarray
and tf.Tensor
:numpy.ndarray
and tf.Tensor
的不同
numpy.ndarray
只能在 CPU 中運行,於主記憶體中tf.Tensor
可以在 CPU 或 GPU 運行。tf.Tensor
和 numpy.ndarray
間轉換:
numpy.ndarray
傳入 tensorflow 的運算元,如 tf.add
tf.Tensor
傳入 numpy 的運算元,如 np.add
。該 tf.Tensor
必須已有 numpy.ndarray
填滿numpy.ndarray
填滿的 tf.Tensor
,其 numpy.ndarray
的值為何,可以使用 tf.Tensor().numpy
屬性。下面的原始碼是一個使用 eager execution 的例子,可以看到在例子裡,numpy.ndarray
和 tf.Tensor
混合運算無障礙。
import tensorflow as tf
tf.enable_eager_execution() # must enable eager mode immedately after importing
print(tf.executing_eagerly()) #outputing True
a = tf.constant([[1, 2],
[3, 4]])
print(a) # creat an usual Tensor object with numpy.ndarray
# => tf.Tensor(
# [[1 2]
# [3 4]], shape=(2, 2), dtype=int32)
b = tf.add(a, 1) # creat another Tensor object by broadcast adding 1
print(b) # => tf.Tensor(
#[[2 3]
#[4 5]], shape=(2, 2), dtype=int32)
import numpy as np
c = np.multiply(a, b)
print(c) # => <class 'numpy.ndarray'> [[ 2 6]
# [12 20]]
不支持 tf.placeholder
:當在 Eager mode 使用 tf.placeholder
,會出現以下錯誤訊息
Problem: RuntimeError: tf.placeholder() is not compatible with eager execution.
這是 tf.placeholder
是為運算元的輸入先建置一個符號,並預留空間,待資料流入計算圖時使用。這樣的需求和 eager execution 的設計不合,因為 eager execution 在實例化 tf.Tensor
物件需要使用者立即提供資料。
[1] A Brief Guide to Tensorflow Eager Execution: introduces 1.7 release
之前一直好奇用Eager mode 做出來的模型效率不是很差嗎?
原來真正使用是要轉成graph mode,請問能分享轉成graph mode的相關介紹嗎@@?
謝謝你的留言!我很希望目前我能夠很詳細的回應你。可是,
因為其實他不是要轉成 graph mode,而是在 eager mode 利用 tf.Saver 存成 checkpoint 格式後,在 graph mode 中讀入。你可以先看看我附上 Tensorflow r1.13 的 tf.contrib.eager.CheckpointableSaver,裡頭有 API 文件解釋該怎麼使用。往後,我若有機會再來細談!Good Luck! https://www.tensorflow.org/versions/r1.13/api_docs/python/tf/contrib/eager/CheckpointableSaver